/*
 *    Copyright (c) 2018-2025, nart All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the pig4cloud.com developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: nart
 */
package com.nai365.nart.blockchain.service.impl;

import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nai365.nart.blockchain.dto.VerificationResDto;
import com.nai365.nart.blockchain.dto.VerifyUserDto;
import com.nai365.nart.blockchain.dto.VerifyUserResDto;
import com.nai365.nart.blockchain.entity.Account;
import com.nai365.nart.blockchain.mapper.AccountMapper;
import com.nai365.nart.blockchain.service.AccountService;
import com.nai365.nart.common.core.constant.SecurityConstants;
import com.nai365.nart.common.core.util.R;
import com.nai365.nart.common.security.util.SecurityUtils;
import com.nai365.nart.member.dto.ChainVerifyUserDto;
import com.nai365.nart.member.entity.Member;
import com.nai365.nart.member.entity.RealName;
import com.nai365.nart.member.feign.RemoteMemberService;
import com.nai365.nart.member.feign.RemoteUmsRealNameService;
import com.reddate.wuhanddc.DDCSdkClient;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * 账户
 *
 * @author pigx code generator
 * @date 2022-06-23 15:31:52
 */
@Service
@AllArgsConstructor
@Slf4j
public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> implements AccountService {


	private DDCSdkClient dDCSdkClient;

	private RestTemplate restTemplate;

	private static final String VURL = "https://zpc.market.alicloudapi.com/efficient/cellphone/post";

	private static final String URL = "https://openapi-ddc.bsnbase.com/ddcoai/sys/v1/opb/account/create/save";

	private static final String RECHARGE_BUSINESS_URL = "https://openapi-ddc.bsnbase.com/ddcoai/sys/v1/opb/account/business/save";

	private static final String RECHARGE_GAS_URL = "https://openapi-ddc.bsnbase.com/ddcoai/sys/v1/opb/account/gas/save";

	private static final String PROOF = "{\"claim\":{\"entName\":\"广西朗朗网络科技有限公司\",\"domain\":\"https://nai365.com\",\"loginName\":\"laoniao857857\",\"did\":\"did:bsn:43ozznpiMFdS9yndxE4S4tTRQbYE\"},\"context\":\"https://www.w3.org/2018/credentials/v1\",\"cptId\":\"882201251518080013\",\"created\":\"2022-06-16 06:42:14\",\"expirationDate\":\"2042-06-16\",\"id\":\"1537324654321078272\",\"issuerDid\":\"did:bsn:2unHZEGYWU5TrcmVnFQ8YGKnLV2h\",\"proof\":{\"creator\":\"did:bsn:2unHZEGYWU5TrcmVnFQ8YGKnLV2h\",\"type\":\"Secp256k1\",\"signatureValue\":\"7thH/5Kum/e4i80QXSfDfcGvyiW7J+4yslcNiwTiJthCxxBHytwy096vmVIdfezjttiL9BGbLByGIdFDH//o8gA=\"},\"shortDesc\":\"DDC业务凭证模板\",\"type\":\"Proof\",\"userDid\":\"did:bsn:43ozznpiMFdS9yndxE4S4tTRQbYE\"}";

	private static final String API_TOKEN = "eyJ0eXAiOiJKV1QiLCJ0eXBlIjoiT1BFTi1BUEktSldUIiwiYWxnIjoiSFMyNTYifQ.eyJsb2dpbk5hbWUiOiJsYW9uaWFvODU3ODU3IiwiZXhwIjo0ODExMDM1MzM0fQ.gN4am1LCYpOsRTDqp2lNW0n1NzdcB5OaPok48my2OuU";

	private String createAccount(Long userId) throws IOException {
		/**
		 * address;
		 * publicKey;
		 * privateKey;
		 * mnemonic;
		 */
		com.reddate.wuhanddc.dto.ddc.Account account = dDCSdkClient.accountService.createAccount();
		//保存数据库
		Account account1 = new Account();

		account1.setChainId(1L)
				.setUserId(userId)
				.setAddress(account.address)
				.setPrivateKey(account.privateKey)
				.setPublicKey(account.publicKey)
				.setMnemonic(account.mnemonic);
		this.save(account1);
		//调用BSNDDC


		CloseableHttpClient httpclient = HttpClients.createDefault();

		HttpPost httpPost = new HttpPost(URL);

		RequestConfig requestConfig = RequestConfig.custom()
				// 设置连接主机服务超时时间
				.setConnectTimeout(1000 * 60 * 10)
				// 设置连接请求超时时间
				.setConnectionRequestTimeout(1000 * 60 * 10)
				// 设置读取数据连接超时时间
				.setSocketTimeout(1000 * 60 * 15)
				.build();
		// 为httpPost实例设置配置
		httpPost.setConfig(requestConfig);

		httpPost.addHeader("Content-Type", "application/json");
		httpPost.addHeader("apitoken", "eyJ0eXAiOiJKV1QiLCJ0eXBlIjoiT1BFTi1BUEktSldUIiwiYWxnIjoiSFMyNTYifQ.eyJsb2dpbk5hbWUiOiJsYW9uaWFvODU3ODU3IiwiZXhwIjo0ODExMDM1MzM0fQ.gN4am1LCYpOsRTDqp2lNW0n1NzdcB5OaPok48my2OuU");

		Map<String, Object> map = new HashMap();
		map.put("opbChainClientName", UUID.randomUUID().toString().replace("-", ""));
		map.put("opbChainClientType", 2);
		map.put("opbChainId", 4);
		map.put("opbClientAddress", account.address);
		map.put("opbKeyType", 3);
		map.put("proof", PROOF);
		map.put("openDdc", 5);
		String jsonString = JSONObject.toJSONString(map);
		StringEntity entity = new StringEntity(jsonString, ContentType.APPLICATION_JSON);
		httpPost.setEntity(entity);

		CloseableHttpResponse response = httpclient.execute(httpPost);
		HttpEntity res = response.getEntity();
		// 通过EntityUtils中的toString方法将结果转换为字符串
		String result = EntityUtils.toString(res, "UTF-8");
		//JSONObject json = JSONObject.parseObject(result);

		System.out.println(result);
		/**
		 * {
		 * "code": 0,
		 * "errorLogCode": null,
		 * "errorLogMessage": "",
		 * "message": "MSG_00000",
		 * "data":{
		 * "opbChainClientAddress": "0x277a62ec110ce3e5f86f04e540babb47abb289ac"
		 * },
		 * "portalToken": null
		 * }
		 */
		JSONObject jsonObject = JSONObject.parseObject(result);
		JSONObject data = jsonObject.getJSONObject("data");
		String opbChainClientAddress = data.getString("opbChainClientAddress");
		return opbChainClientAddress;
	}


	private RemoteUmsRealNameService remoteUmsRealNameService;

	private RemoteMemberService remoteMemberService;


	@Override
	public R<VerifyUserResDto> verifyUser(VerifyUserDto verifyUserDto) {
		//1.用户认证
		VerificationResDto verificationResDto = getVerificationResDto(verifyUserDto);
		if (verificationResDto.getResult().getVerificationResult().equals("1")) {
			RealName realNameByPhone = remoteUmsRealNameService.findRealNameByPhone(verifyUserDto.getPhone(), SecurityConstants.FROM_IN);

			if (ObjectUtils.isEmpty(realNameByPhone)) {
				//将RealName保存到数据库
				RealName realName = new RealName();
				realName.setIdCard(verifyUserDto.getIdCard());
				realName.setName(verifyUserDto.getRealName());
				realName.setPhone(verifyUserDto.getPhone());
				if (SecurityUtils.getUser() != null) {
					//TODO
					Long userId = SecurityUtils.getUser().getId();
					realName.setUserId(userId);
				}
				//TODO
				//realName.setUserId(1546686580449607682L);
				remoteUmsRealNameService.save(realName, SecurityConstants.FROM_IN);
			}
			//检查是否上链
			Member memberByPhone = remoteMemberService.findMemberByPhone(verifyUserDto.getPhone(), SecurityConstants.FROM_IN);
			//已上链
			VerifyUserResDto verifyUserResDto = new VerifyUserResDto();
			if (memberByPhone != null && memberByPhone.getIsVerify() == 1) {
				verifyUserResDto.setIdCard(verifyUserDto.getIdCard());
				verifyUserResDto.setOpbChainClientAddress(memberByPhone.getOpbChainClientAddress());
				verifyUserResDto.setPhone(verifyUserDto.getPhone());
				verifyUserResDto.setRealName(verifyUserDto.getRealName());
				verifyUserResDto.setIsSuccess(true);
				return R.ok(verifyUserResDto, "认证成功!");
			} else {
				//创建账户上链
				String opbChainClientAddress = null;
				try {
					opbChainClientAddress = createAccount(memberByPhone.getUserId());
				} catch (IOException e) {
					e.printStackTrace();
				}
				//同时更新member表中字段
				ChainVerifyUserDto chainVerifyUserDto = new ChainVerifyUserDto();
				chainVerifyUserDto.setChainAdress(opbChainClientAddress);
				chainVerifyUserDto.setIsVerify(1);
				chainVerifyUserDto.setRealName(verifyUserDto.getRealName());
				if (SecurityUtils.getUser() != null) {

					Long userId = SecurityUtils.getUser().getId();
					chainVerifyUserDto.setUserId(userId);
				}
				//更新数据库中的记录
				remoteMemberService.updateMemberIsVerify(chainVerifyUserDto, SecurityConstants.FROM_IN);

				verifyUserResDto.setIsSuccess(true);
				verifyUserResDto.setRealName(verifyUserDto.getRealName());
				verifyUserResDto.setPhone(verifyUserDto.getPhone());
				verifyUserResDto.setOpbChainClientAddress(opbChainClientAddress);
				verifyUserResDto.setIdCard(verifyUserDto.getIdCard());
				return R.ok(verifyUserResDto, "认证成功!");
			}

		} else {
			//真实信息认证失败 VerifyUserResDto
			VerifyUserResDto verifyUserResDto = new VerifyUserResDto();
			verifyUserResDto.setIsSuccess(false);
			verifyUserResDto.setIdCard(verifyUserDto.getIdCard());
			verifyUserResDto.setRealName(verifyUserDto.getRealName());
			verifyUserResDto.setPhone(verifyUserDto.getPhone());
			return R.failed(verifyUserResDto, "认证失败!");
		}

	}


	private static VerificationResDto getVerificationResDto(VerifyUserDto verifyUserDto) {
		Map<String, String> headers = new HashMap();
		headers.put("Authorization", "APPCODE 7a6544e71a9e4518af0c9cd8bf996ce8");

		Map<String, Object> map = new HashMap();
		map.put("idCard", verifyUserDto.getIdCard());
		map.put("mobile", verifyUserDto.getPhone());
		map.put("realName", verifyUserDto.getRealName());
		String body = HttpUtil.createPost(VURL).addHeaders(headers).form(map).execute().body();

		System.out.println(body);

		VerificationResDto resDto = JSONUtil.toBean(body, VerificationResDto.class);
		return resDto;
	}

	private HttpPost getHttpPost() {
		HttpPost httpPost = new HttpPost(URL);
		RequestConfig requestConfig = RequestConfig.custom()
				// 设置连接主机服务超时时间
				.setConnectTimeout(1000 * 60 * 10)
				// 设置连接请求超时时间
				.setConnectionRequestTimeout(1000 * 60 * 10)
				// 设置读取数据连接超时时间
				.setSocketTimeout(1000 * 60 * 15)
				.build();
		// 为httpPost实例设置配置
		httpPost.setConfig(requestConfig);
		httpPost.addHeader("Content-Type", "application/json");
		httpPost.addHeader("apitoken", "eyJ0eXAiOiJKV1QiLCJ0eXBlIjoiT1BFTi1BUEktSldUIiwiYWxnIjoiSFMyNTYifQ.eyJsb2dpbk5hbWUiOiJsYW9uaWFvODU3ODU3IiwiZXhwIjo0ODExMDM1MzM0fQ.gN4am1LCYpOsRTDqp2lNW0n1NzdcB5OaPok48my2OuU");
		return httpPost;
	}

	public void rechargeBusiness(String address, BigDecimal money) throws Exception {
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.APPLICATION_JSON);
		headers.add("apitoken", API_TOKEN);
		Map<String, Object> map = new HashMap<>();
		map.put("businessMoney", money.multiply(new BigDecimal(100)).longValue());
		map.put("opbChainClientAddress", address);
		map.put("opbChainId", 4);
		map.put("proof", PROOF);
		map.put("reqTransactionSn", UUID.randomUUID().toString().replace("-", ""));
		String jsonString = JSONObject.toJSONString(map);
		HttpResponse response = HttpRequest.post(RECHARGE_BUSINESS_URL).body(jsonString).header(headers).execute();
		if (response.getStatus() != 200) {
			throw new Exception(response.getStatus() + "");
		}
		String body = response.body();
		log.debug(body);
		JSONObject jsonObject = JSONObject.parseObject(body);
		int code = jsonObject.getInteger("code");
		if (code != 0) {
			throw new Exception(jsonObject.getString("message"));
		}

	}

	@Override
	public void rechargeGas(String address, BigDecimal money) throws Exception {
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.APPLICATION_JSON);
		headers.add("apitoken", API_TOKEN);
		Map<String, Object> map = new HashMap<>();
		map.put("businessMoney", money.multiply(new BigDecimal(100)).longValue());
		map.put("opbChainClientAddress", address);
		map.put("opbChainId", 4);
		map.put("proof", PROOF);
		map.put("reqTransactionSn", UUID.randomUUID().toString().replace("-", ""));
		String jsonString = JSONObject.toJSONString(map);
		HttpResponse response = HttpRequest.post(RECHARGE_GAS_URL).body(jsonString).header(headers).execute();
		if (response.getStatus() != 200) {
			throw new Exception(response.getStatus() + "");
		}
		String body = response.body();
		log.debug(body);
		JSONObject jsonObject = JSONObject.parseObject(body);
		int code = jsonObject.getInteger("code");
		if (code != 0) {
			throw new Exception(jsonObject.getString("message"));
		}
	}

	@Override
	public Account findByAddress(String address) {
		LambdaQueryWrapper<Account> queryWrapper = Wrappers.lambdaQuery();
		queryWrapper.eq(Account::getAddress, address);
		List<Account> accountList = this.list(queryWrapper);
		if (!accountList.isEmpty()) {
			return accountList.get(0);
		}
		return null;
	}
}

